/*
 * Antichat Web Tool
 *
 * [C] Great, Antichat.
 *
 * http://antichat.ru
 *
 *
 * Encoder/decoder plugin; main coding engine
 */

#include <string>
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include "coder.h"


bool is_alpha(char in)
{
	return (in>='a' && in<='z') || (in>='A' && in<='Z');
}

//
// UrlEncode
//
// Converts string into URL format
//
//  lpszInputString - input buffer
//  lpOutputBuffer  - output buffer (space for it should be allocated before function call)
//  nMaxLength      - size of output buffer
//  bEncodeAll      - encode all symbols or only nonprintable?
//
// Return value:
//  Number of bytes really written to output buffer
//

ULONG
UrlEncode (
  LPTSTR lpszInputString,
  LPTSTR lpOutputBuffer,
  SIZE_T nMaxLength,
  BOOL   bEncodeAll
  )
{
	if( nMaxLength < 3 )
		return 0;

	*lpOutputBuffer = 0;
	int outpos = 0;
	for( int i=0; i<lstrlen(lpszInputString); i++ )
	{
		unsigned char in = (unsigned char) lpszInputString[i];

		if( bEncodeAll || !( is_alpha(in) || isdigit(in) ) )
		{
			wsprintf( lpOutputBuffer + lstrlen(lpOutputBuffer), "%%%02X", in );
			outpos += 3;
		}
		else
		{
			lpOutputBuffer[outpos] = in;
			lpOutputBuffer[outpos+1] = 0;
			outpos ++;
		}
		
		if( outpos+3 >= nMaxLength )
			break;
	}
	
	lpOutputBuffer[outpos] = 0;
	return outpos;
}


//
// UrlDecode
//
// Decodes URL formatted string
//

ULONG
UrlDecode (
  LPTSTR lpszInputString,
  LPTSTR lpOutputBuffer,
  SIZE_T nMaxLength
  )
{
	int outpos = 0;
	for( int i=0; i<lstrlen(lpszInputString); outpos++ )
	{
		if( lpszInputString[i] == '%' )
		{
			char temp[3] = {0,0,0};
			*(WORD*)temp = *(WORD*)&lpszInputString[i+1];

			char val;
			sscanf( temp, "%x", &val );

			lpOutputBuffer[outpos] = val;
			
			i += 3;
		}
		else lpOutputBuffer[outpos] = lpszInputString[i++];
	}

	lpOutputBuffer[outpos] = 0;
	return outpos;
}


//
// Base64Encode
//
// Encodes string in base64
//

static char charBase64[] = {
	'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
	'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
	'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
	'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};

ULONG
Base64Encode (
  LPTSTR lpszInputString,
  LPTSTR lpOutputBuffer,
  SIZE_T nMaxLength
  )
{
	char chr[3], enc[4];

	int outpos = 0;

	for( int i=0; i<lstrlen(lpszInputString); i+=3 )
	{
		if( outpos+4 >= nMaxLength )
			break;

		chr[0] = lpszInputString[i];
		chr[1] = lpszInputString[i+1];
		chr[2] = lpszInputString[i+2];

		enc[0] = chr[0] >> 2;
		enc[1] = ((chr[0] & 0x03) << 4) | (chr[1] >> 4);
		enc[2] = ((chr[1] & 0x0F) << 2) | (chr[2] >> 6);
		enc[3] = chr[2] & 0x3F;

		lpOutputBuffer[outpos++] = charBase64[enc[0]];
		lpOutputBuffer[outpos++] = charBase64[enc[1]];

		if( i+1 >= lstrlen(lpszInputString) )
		{
			lpOutputBuffer[outpos++] = '=';
			lpOutputBuffer[outpos++] = '=';
		}
		else if( i+2 >= lstrlen(lpszInputString) )
		{
			lpOutputBuffer[outpos++] = charBase64[enc[2]];
			lpOutputBuffer[outpos++] = '=';
		}
		else
		{
			lpOutputBuffer[outpos++] = charBase64[enc[2]];
			lpOutputBuffer[outpos++] = charBase64[enc[3]];
		}
	}

	lpOutputBuffer[outpos] = 0;
	return outpos;
}


//
// Base64Decode
//
// Decodes string from base64
//

static int indexBase64[] = {
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
	52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
	-1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
	15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
	-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
	41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
	-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};


ULONG
Base64Decode (
  LPTSTR lpszInputString,
  LPTSTR lpOutputBuffer,
  SIZE_T nMaxLength
  )
{
	char chr[3], enc[4];

	int outpos = 0;

	for( int i=0; i<lstrlen(lpszInputString); i+=4 )
	{
		if( outpos+3 >= nMaxLength )
			break;

		enc[0] = indexBase64[lpszInputString[i]];
		enc[1] = indexBase64[lpszInputString[i+1]];
		enc[2] = indexBase64[lpszInputString[i+2]];
		enc[3] = indexBase64[lpszInputString[i+3]];

		if( enc[0] == -1 || enc[1] == -1 )
			break;

		chr[0] = (enc[0] << 2) | (enc[1] >> 4);
		chr[1] = ((enc[1] & 15) << 4) | (enc[2] >> 2);
		chr[2] = ((enc[2] & 3) << 6) | enc[3];

		lpOutputBuffer[outpos++] = chr[0];

		if( enc[2] != -1 )
		{
			lpOutputBuffer[outpos++] = chr[1];
		}

		if( enc[3] != -1 )
		{
			lpOutputBuffer[outpos++] = chr[2];
		}
	}

	lpOutputBuffer[outpos] = 0;
	return outpos;
}


//
// Md5Hash
//
// Calculate MD5 digest for input string. Output buffer should be enough to place 32 symbols
//

VOID
Md5Hash (
  LPTSTR lpszInputString,
  LPTSTR lpOutputBuffer
  )
{
	//
	// I don't sure in this code, maybe it will be more correct to call LoadLibrary directly
	//

	HMODULE hAdvApi32 = GetModuleHandle( "advapi32.dll" );
	if( !hAdvApi32 )
		hAdvApi32 = LoadLibrary( "advapi32.dll" );

	// Get Addresses

	void (WINAPI *MD5Init)(MD5_CTX*);
	void (WINAPI *MD5Update)(MD5_CTX*,LPCTSTR,UINT);
	void (WINAPI *MD5Final)(MD5_CTX*);

	*(FARPROC*)&MD5Init   = GetProcAddress( hAdvApi32, "MD5Init"   );
	*(FARPROC*)&MD5Update = GetProcAddress( hAdvApi32, "MD5Update" );
	*(FARPROC*)&MD5Final  = GetProcAddress( hAdvApi32, "MD5Final"  );

	MD5_CTX ctx = {0};
	MD5Init( &ctx );
	MD5Update( &ctx, lpszInputString, lstrlen(lpszInputString) );
	MD5Final( &ctx );

	*lpOutputBuffer = 0;

	for( int i=0;i<16;i++ )
		wsprintf( lpOutputBuffer + lstrlen(lpOutputBuffer), "%02x", ctx.digest[i] );
}


